package org.apache.james.mime4j.parser;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.LinkedList;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.decoder.Base64InputStream;
import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
import org.apache.james.mime4j.descriptor.BodyDescriptor;
import org.apache.james.mime4j.io.BufferedLineReaderInputStream;
import org.apache.james.mime4j.io.RootInputStream;
import org.apache.james.mime4j.util.MimeUtil;

public class MimeTokenStream
  implements EntityStates, RecursionMode
{
  private final MimeEntityConfig config;
  private EntityStateMachine currentStateMachine;
  private final LinkedList entities;
  private BufferedLineReaderInputStream inbuffer;
  private int recursionMode;
  private RootInputStream rootInputStream;
  private int state;

  public MimeTokenStream()
  {
    this(new MimeEntityConfig());
  }

  protected MimeTokenStream(MimeEntityConfig paramMimeEntityConfig)
  {
    this.entities = new LinkedList();
    this.state = -1;
    this.recursionMode = 0;
    this.config = paramMimeEntityConfig;
  }

  public static final MimeTokenStream createMaximalDescriptorStream()
  {
    MimeEntityConfig localMimeEntityConfig = new MimeEntityConfig();
    localMimeEntityConfig.setMaximalBodyDescriptor(true);
    return new MimeTokenStream(localMimeEntityConfig);
  }

  public static final MimeTokenStream createStrictValidationStream()
  {
    MimeEntityConfig localMimeEntityConfig = new MimeEntityConfig();
    localMimeEntityConfig.setStrictParsing(true);
    return new MimeTokenStream(localMimeEntityConfig);
  }

  private void doParse(InputStream paramInputStream, String paramString)
  {
    this.entities.clear();
    this.rootInputStream = new RootInputStream(paramInputStream);
    this.inbuffer = new BufferedLineReaderInputStream(this.rootInputStream, 4096, this.config.getMaxLineLen());
    switch (this.recursionMode)
    {
    default:
    case 2:
    case 0:
    case 1:
    case 3:
    }
    while (true)
    {
      while (true)
      {
        this.entities.add(this.currentStateMachine);
        this.state = this.currentStateMachine.getState();
        return;
        this.currentStateMachine = new RawEntity(this.inbuffer);
      }
      MimeEntity localMimeEntity = new MimeEntity(this.rootInputStream, this.inbuffer, null, 0, 1, this.config);
      localMimeEntity.setRecursionMode(this.recursionMode);
      if (paramString != null)
        localMimeEntity.skipHeader(paramString);
      this.currentStateMachine = localMimeEntity;
    }
  }

  public static final String stateToString(int paramInt)
  {
    return AbstractEntity.stateToString(paramInt);
  }

  public BodyDescriptor getBodyDescriptor()
  {
    return this.currentStateMachine.getBodyDescriptor();
  }

  public InputStream getDecodedInputStream()
  {
    String str = getBodyDescriptor().getTransferEncoding();
    Object localObject = this.currentStateMachine.getContentStream();
    if (MimeUtil.isBase64Encoding(str))
      localObject = new Base64InputStream((InputStream)localObject);
    while (true)
    {
      do
        return localObject;
      while (!(MimeUtil.isQuotedPrintableEncoded(str)));
      localObject = new QuotedPrintableInputStream((InputStream)localObject);
    }
  }

  public String getField()
  {
    return this.currentStateMachine.getField();
  }

  public String getFieldName()
  {
    return this.currentStateMachine.getFieldName();
  }

  public String getFieldValue()
  {
    return this.currentStateMachine.getFieldValue();
  }

  public InputStream getInputStream()
  {
    return this.currentStateMachine.getContentStream();
  }

  public Reader getReader()
  {
    Charset localCharset;
    String str = getBodyDescriptor().getCharset();
    if ((str == null) || ("".equals(str)))
      localCharset = Charset.forName("US-ASCII");
    while (true)
    {
      return new InputStreamReader(getDecodedInputStream(), localCharset);
      localCharset = Charset.forName(str);
    }
  }

  public int getRecursionMode()
  {
    return this.recursionMode;
  }

  public int getState()
  {
    return this.state;
  }

  public boolean isRaw()
  {
    int i;
    if (this.recursionMode == 2)
      i = 1;
    while (true)
    {
      return i;
      i = 0;
    }
  }

  public int next()
    throws IOException, MimeException
  {
    if ((this.state == -1) || (this.currentStateMachine == null))
      throw new IllegalStateException("No more tokens are available.");
    do
    {
      this.entities.removeLast();
      if (!(this.entities.isEmpty()))
        break label113;
      this.currentStateMachine = null;
      if (this.currentStateMachine == null)
        break label143;
      EntityStateMachine localEntityStateMachine = this.currentStateMachine.advance();
      if (localEntityStateMachine != null)
      {
        this.entities.add(localEntityStateMachine);
        this.currentStateMachine = localEntityStateMachine;
      }
      this.state = this.currentStateMachine.getState();
    }
    while (this.state == -1);
    int i = this.state;
    while (true)
    {
      while (true)
      {
        return i;
        label113: this.currentStateMachine = ((EntityStateMachine)this.entities.getLast());
        this.currentStateMachine.setRecursionMode(this.recursionMode);
      }
      label143: this.state = -1;
      i = this.state;
    }
  }

  public void parse(InputStream paramInputStream)
  {
    doParse(paramInputStream, null);
  }

  public void parseHeadless(InputStream paramInputStream, String paramString)
  {
    if (paramString == null)
      throw new IllegalArgumentException("Content type may not be null");
    doParse(paramInputStream, paramString);
  }

  public void setRecursionMode(int paramInt)
  {
    this.recursionMode = paramInt;
    if (this.currentStateMachine != null)
      this.currentStateMachine.setRecursionMode(paramInt);
  }

  public void stop()
  {
    this.inbuffer.clear();
    this.rootInputStream.truncate();
  }
}